// TEST
package de.akabahn.ebd.anlage.util;

import de.akabahn.ebd.anlage.Abschnitt;
import de.akabahn.ebd.anlage.Anlage;
import de.akabahn.ebd.anlage.Betriebsstelle;
import de.akabahn.ebd.anlage.HaltAbschnitt;
import de.akabahn.ebd.anlage.Signal;
import java.beans.XMLEncoder;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import org.apache.commons.collections4.map.CaseInsensitiveMap;
import org.ini4j.Ini;
import org.ini4j.Profile;

/**
 * Read in
 * @author moschlar
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws IOException {
        String prefix = "/home/moschlar/src/fgbs/Befehlssystem/src/main/webapp/WEB-INF/anlage";
        String betriebsstellendatei =  prefix + "/" + "betriebsstellen.db";
        String gleisnamendatei = prefix + "/" + "gleisnamen";
        String anlagendatei = prefix + "/" + "ebd.bdb";

        Anlage anlage = read(betriebsstellendatei, gleisnamendatei, anlagendatei);

        System.out.println(anlage);

//        Betriebsstelle betriebsstelle = anlage.getBetriebsstelle("ZDK");
//        System.out.println(betriebsstelle);
//        Signal signal = anlage.getSignal(betriebsstelle, "P3");
//        System.out.println(signal);
//        System.out.println(signal.getAbschnitt());
//        System.out.println(anlage.getSignal(anlage.getBetriebsstelle("ZDG"), "Z").getAbschnitt());

        try (XMLEncoder xmlEncoder = new XMLEncoder(new FileOutputStream(Main.class.getClassLoader().getResource("anlage.xml").getPath()))) {
            xmlEncoder.writeObject(anlage);
        }

//        System.out.println(Arrays.toString(args));
//        if (args.length >= 3) {
//            try {
//                Anlage anlage = read(args[0], args[1], args[2]);
//            } catch (IOException ex) {
//                System.err.println(ex.toString());
//            }
//        } else {
//            System.err.println("Not enough arguments.");
//        }
        
    }

    /**
     * Create a new Anlage. Creates Betriebsstellen, Abschnitte and Signale by
     *  reading the supplied configuration files.
     * @param betriebsstellendatei
     * @param gleisnamendatei
     * @param anlagendatei
     * @throws IOException
     */
    private static Anlage read(String betriebsstellendatei, String gleisnamendatei, String anlagendatei) throws IOException {
        Map<String, String> ds100 = new CaseInsensitiveMap<String, String>();
        Map<String, Betriebsstelle> betriebsstellen = new CaseInsensitiveMap<String, Betriebsstelle>();
        Map<String, Abschnitt> abschnitte = new CaseInsensitiveMap<String, Abschnitt>();
        Map<String, Signal> signale = new CaseInsensitiveMap<String, Signal>();

        Ini betriebsstellenConfig = new Ini(new File(betriebsstellendatei));
        Map<String, String> betriebsstellen_nachbarn = new CaseInsensitiveMap<String, String>();
        // First, create all Betriebsstellen from the config file
        for (Ini.Section section : betriebsstellenConfig.values()) {
            Betriebsstelle betriebsstelle = new Betriebsstelle();

            betriebsstelle.setDS100(section.getName());

            betriebsstelle.setName(section.get("name"));
            betriebsstelle.setNummer(section.get("nummer", Integer.class));
            betriebsstelle.setTyp(Betriebsstelle.Typ.fromString(section.get("typ")));
            betriebsstelle.setGleise(new ArrayList<String>(Arrays.asList(section.get("gleise", "").split(","))));

            ds100.put(betriebsstelle.getName(), betriebsstelle.getDS100());
            betriebsstellen.put(betriebsstelle.getDS100(), betriebsstelle);
            betriebsstellen_nachbarn.put(betriebsstelle.getDS100(), section.get("nachbarn"));
        }
        // Now, connect them to their neighbours
        for (String s : betriebsstellen_nachbarn.keySet()) {
            if (betriebsstellen_nachbarn.get(s) != null) {
                ArrayList<Betriebsstelle> nachbarn = new ArrayList<Betriebsstelle>();
                for (String n : betriebsstellen_nachbarn.get(s).split(",")) {
                    nachbarn.add(betriebsstellen.get(n));
                }
                betriebsstellen.get(s).setNachbarn(nachbarn);
            }
        }
        betriebsstellenConfig = null; betriebsstellen_nachbarn = null;

        Map<String, String> gleisnamen = new CaseInsensitiveMap<String, String>();
        try (BufferedReader bufferedReader = new BufferedReader(new FileReader(gleisnamendatei))) {
            for (String line; (line = bufferedReader.readLine()) != null;) {
                if (!line.isEmpty() && !line.startsWith("#")) {
                    String[] split = line.split("\\s", 2);
                    gleisnamen.put(split[0], split[1]);
                }
            }
        }

        Ini abschnittsConfig = new Ini(new File(anlagendatei));
        for (Profile.Section section : abschnittsConfig.values()) {
            Abschnitt abschnitt = new Abschnitt();

            String[] split = section.getName().split(",", 2);
            String name = split[0];
            String bedingung = (split.length == 2) ? split[1] : null;
            abschnitt.setName(name);
            abschnitt.setBedingung(bedingung);

            abschnitt.setGleisname(gleisnamen.remove(abschnitt.getName()));

            //String psig = section.get("psig");
            //String pha = section.get("pha");
            //String php = section.get("php");
            //List<String> pws = section.getAll("pws");

            String _psig = section.get("psig");
            if (_psig != null) {
                Signal psig = new Signal();
                psig.setName(_psig);
                psig.setAbschnitt(abschnitt);
                abschnitt.setPsig(psig);
                if (section.get("pha") != null) {
                    HaltAbschnitt pha = new HaltAbschnitt(section.get("pha"));
                    psig.setHaltabschnitt(pha);
                    abschnitt.setPha(pha);
                }
                if (section.get("php") != null) {
                    HaltAbschnitt php = new HaltAbschnitt(section.get("php"));
                    psig.setHalteplatzabschnitt(php);
                    abschnitt.setPhp(php);
                }
                if (!_psig.equals("NULL") && !_psig.equals("FAHRT")) {
                    if (!signale.containsKey(psig.getName())) {
                        signale.put(psig.getName(), psig);
                    } else {
                        // TODO
                        System.err.println(psig.getName() + " already in signale");
                    }
                }
            }

            //String gsig = section.get("gsig");
            //String gha = section.get("gha");
            //String ghp = section.get("ghp");
            //List<String> gws = section.getAll("gws");

            String _gsig = section.get("gsig");
            if (_gsig != null) {
                Signal gsig = new Signal();
                gsig.setName(_gsig);
                gsig.setAbschnitt(abschnitt);
                abschnitt.setGsig(gsig);
                if (section.get("gha") != null) {
                    HaltAbschnitt gha = new HaltAbschnitt(section.get("gha"));
                    gsig.setHaltabschnitt(gha);
                    abschnitt.setGha(gha);
                }
                if (section.get("ghp") != null) {
                    HaltAbschnitt ghp = new HaltAbschnitt(section.get("ghp"));
                    gsig.setHalteplatzabschnitt(ghp);
                    abschnitt.setGhp(ghp);
                }
                if (!_gsig.equals("NULL") && !_gsig.equals("FAHRT")) {
                    if (!signale.containsKey(gsig.getName())) {
                        signale.put(gsig.getName(), gsig);
                    } else {
                        // TODO
                        System.err.println(gsig.getName() + " already in signale");
                    }
                }
            }

            if (!abschnitte.containsKey(abschnitt.getName())) {
                abschnitte.put(abschnitt.getName(), abschnitt);
            } else {
                // TODO
                System.err.println(abschnitt.getName() + " already in abschnitte");
            }

        }

        return new Anlage(ds100, betriebsstellen, abschnitte, signale);
    }

}
